/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       dialog_combat_results.cpp

	$Header: /game/combat_results_dialog.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "dialog_combat_results.h"

#include "adventure_map.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bitmap_layer_cache_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "combat_context.h"
#include "combat_model_window.h"
#include "combat_result.h"
#include "creature_icon_window.h"
#include "creature_select_window.h"
#include "creature_traits.h"
#include "creature_array.h"
#include "external_string.h"
#include "format_string.h"
#include "hero_keyword_replacer.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "music.h"
#include "player.h"
#include "replace_keywords.h"
#include "report_combat_results.h"
#include "sound.h"
#include "sound_cache.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "town.h"


static t_bitmap_group_cache g_layout( "dialog.combat_results" );
extern t_bitmap_group_cache const k_creature_select_bitmaps;
extern t_button_cache g_ok_button;


namespace
{
	enum t_combat_cinematic_result
	{
		k_cinematic_result_none = -1,
		k_cinematic_result_enemy_captured_town,
		k_cinematic_result_enemy_won_battle,
		k_cinematic_result_player_captured_town,
		k_cinematic_result_player_surrendered,
		k_cinematic_result_player_gated,
		k_cinematic_result_player_retreated,
		k_cinematic_result_player_defended_town,
		k_cinematic_result_player_won_battle,
		k_cinematic_result_both_lost,
		k_cinematic_result_count
	};
}


// -----------------------------------------------------------------------
// format hero list as a string
// this function fully expects there to actually be heroes in the array
// this should never be called otherwise
// -----------------------------------------------------------------------
static t_external_string const k_the_army( "the_army.combat" );

static std::string format_hero_list( t_creature_array const& army, std::string const& singular,
									 std::string const& plural )
{
	int						count = 0;
	t_hero_keyword_replacer replacer;
	int						i;
	t_hero const*			hero;

	for (i = 0; i < t_creature_array::k_size; ++i)
	{
		hero = army[i].get_hero();

		if (hero == 0)
			continue;
		++count;
		replacer.add_hero( hero );
	}
	
	if (count == 0)
		return replace_keywords( singular, "%hero_name", k_the_army );

	if (count == 1)
		return replacer( singular );
	return replacer( plural );
}

// ---------------------------------------------------------------------
// combat_results dialog
// ---------------------------------------------------------------------
t_combat_results_dialog::t_combat_results_dialog( t_window*					parent, 
												  t_creature_array**		armies,
												  t_player**				players,
												  t_creature_array*			losses,
												  t_combat_result			result,
												  t_town const*				town,
												  t_adv_map_point const&	location,
												  t_creature_stack_ptr ( & leaders )[ 2 ] )
				: t_bitmap_layer_window( 0, t_screen_point(0,0) ),
				  m_parent( parent ),
				  m_result( result ) 
{
	int i;

	m_losses = losses;
	m_town = town;
	m_location = location;
	for (i = 0; i < 2; ++i)
	{
		m_armies[i] = armies[i];
		m_leaders[i] = leaders[i];
		m_players[i] = players[i];
	}
	initialize();
}

// ---------------------------------------------------------------------
// add a text item
// ---------------------------------------------------------------------
t_text_window* t_combat_results_dialog::add_text( std::string const& text, std::string const& layer_name, 
							               int size, bool size_explicit, bool center_vertical )
{
	t_bitmap_layer const* layer;
	t_screen_rect         rect;
	t_text_window*        text_window;
	t_cached_font         font;

	layer = m_layout->find( layer_name );
	rect = layer->get_rect();
	if( size_explicit )
		font = get_font( size );
	else
		font = get_font( rect.height() / size );
	text_window = new t_text_window( font, rect, this, text, t_pixel_24(0,0,0));
	text_window->set_center_horizontal();
	if( center_vertical )
		text_window->set_center_vertical();
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200));
	return text_window;
}

// ---------------------------------------------------------------------
// add a text item from creature select box
// ---------------------------------------------------------------------
t_text_window* t_combat_results_dialog::add_text_creature_select( std::string const& text, std::string const& layer_name, 
							               int size, t_screen_point point, bool size_explicit )
{
	t_bitmap_layer const* layer;
	t_screen_rect         rect;
	t_text_window*        text_window;
	t_cached_font         font;

	layer = m_creatures_lost_layout->find( layer_name );
	rect = layer->get_rect();
	rect.left += point.x;
	rect.top += point.y;
	if( size_explicit )
		font = get_font( size );
	else
		font = get_font( rect.height() / size );
	text_window = new t_text_window( font, rect, this, text, t_pixel_24(0,0,0));
	text_window->set_center_horizontal();
	text_window->set_drop_shadow( true, t_pixel_24(200,200,200));
	return text_window;
}

// -----------------------------------------------------------------------
// combat_results creatures dialog
// -----------------------------------------------------------------------
void t_combat_results_dialog::ok_clicked( t_button* button )
{
//	m_return_value = false;
	close();	// close all child windows too
}

// ---------------------------------------------------------------------
// create buttons
// ---------------------------------------------------------------------
void t_combat_results_dialog::create_buttons()
{
	t_screen_rect rect;
	t_button*     button;
	t_help_block const& help = get_help_block( "shared" );


	// create ok button
	rect = m_layout->find( "ok_button" )->get_rect();
	button = new t_button( g_ok_button.get(), rect.top_left(), this );
	button->set_click_handler( bound_handler(*this, &t_combat_results_dialog::ok_clicked ) );
	set_help( button, help, "ok" );
}

// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
static void set_creature( t_bitmap_layer_cache_window* window, t_abstract_creature const* stack, int size, bool force_awake_portrait )
{
	t_bitmap_layer_ptr icon;

	icon = stack->get_portrait( size, force_awake_portrait );
	window->set_bitmap( icon );
	window->set_help_balloon_text( stack->get_name() );
}

// ---------------------------------------------------------------------
// create icons
// ---------------------------------------------------------------------
void t_combat_results_dialog::create_icons()
{
	t_bitmap_layer const* layer;
	t_window*             window;
	t_bitmap_layer_cache_window* portrait_window;	
	t_screen_point        point(0,0);
	t_screen_rect         rect;
	int i;

	bool winning_side = k_side_attacker;
	if ( defender_won( m_result ) )
		winning_side = k_side_defender;


	layer = m_layout->find( "winner_portrait" );
	portrait_window = new t_bitmap_layer_cache_window(	t_bitmap_layer_ptr(), 
														layer->get_rect().top_left(), 
														this, false );
	if (m_leaders[winning_side] != 0)
		set_creature( portrait_window, m_leaders[winning_side], 82, true );

	layer = m_layout->find( "loser_portrait" );
	portrait_window = new t_bitmap_layer_cache_window(	t_bitmap_layer_ptr(), 
														layer->get_rect().top_left(), 
														this, false );
	if (m_leaders[!winning_side] != 0)
		set_creature( portrait_window, m_leaders[!winning_side], 82, true );

	//winner frame
	layer = m_layout->find( "winner_frame" );
	window = new t_bitmap_layer_window( layer, point, this );

	//loser frame
	layer = m_layout->find( "loser_frame" );
	window = new t_bitmap_layer_window( layer, point, this );

    // show the winner creatures lost
	layer = m_layout->find( "winner_rings" );
	rect = layer->get_rect();
	point.x = rect.left;
	point.y = rect.top;
	t_creature_select_window * creature_window = new t_creature_select_window( point, false, this );
	for (i = 0; i < t_creature_array::k_size; i++)
	{
		if( m_losses[winning_side][i].get_number() != 0 )
			creature_window->add( &m_losses[winning_side][i], true, true );
	}

    // show the loser creatures lost
	layer = m_layout->find( "loser_rings" );
	rect = layer->get_rect();
	point.x = rect.left;
	point.y = rect.top;
	creature_window = new t_creature_select_window( point, false, this );
	for (i = 0; i < t_creature_array::k_size; i++)
	{
		if( m_losses[!winning_side][i].get_number() != 0 )
			creature_window->add( &m_losses[!winning_side][i], true, true );
	}

	//cut scene frame
	layer = m_layout->find( "cut_scene_frame" );
	point.x = point.y = 0;
	window = new t_bitmap_layer_window( layer, point, this );
}

static std::string get_destination_name( t_adventure_map*			map,
										 t_player*					player,
										 t_adv_map_point const&		location,
										 t_creature_array&			creatures,
										 t_town const*				town )
{

	// Find the nearest town with an open space
	// (Note: the location we've been passed was originally extracted from a town, so we assume
	//  we'll be able to go back and find the town it's associated with.)
	t_town const*           destination_town;
	t_adv_map_point		    destination_location;

	destination_town = find_nearest_town( map, player, location, destination_location, 
										  &creatures, town, 0, 0, true );
	return destination_town->get_name();
}

// ---------------------------------------------------------------------
// create all the text to go in each text box
// ---------------------------------------------------------------------
static t_sound_cache const k_sound_won( "combat.win" );
static t_sound_cache const k_sound_lost( "combat.lose" );
static t_external_string const k_enemy_surrenders( "enemy_surrenders.combat" );
static t_external_string const k_enemy_retreats( "enemy_retreats.combat" );
static t_external_string const k_enemy_captures_town( "enemy_captures_town.combat" );
static t_external_string const k_enemy_heroes_gate( "enemy_heroes_gate.combat" );
static t_external_string const k_player_won_battle( "player_won_battle.combat" );
static t_external_string const k_player_surrenders( "player_surrenders.combat" );
static t_external_string const k_player_retreats( "player_retreats.combat" );
static t_external_string const k_one_hero_retreats( "one_hero_retreats.combat" );
static t_external_string const k_player_loses_battle( "player_loses_battle.combat" );
static t_external_string const k_player_heroes_gate( "player_heroes_gate.combat" );
static t_external_string const k_both_died( "both_died.combat" );
static t_external_string const k_victorious( "victorious.combat" );
static t_external_string const k_defeated( "defeated.combat" );
static t_external_string const k_creatures_lost_victor( "creatures_lost_victor.combat" );
static t_external_string const k_creatures_lost_loser( "creatures_lost_loser.combat" );

void t_combat_results_dialog::create_text()
{
	std::string text;
	std::string victor_text;
	t_bitmap_layer const* layer;
	t_screen_point        point(0,0);
	t_screen_rect         rect;
	t_combat_cinematic_result	cinematic_result = k_cinematic_result_none; 

	t_adventure_map* map_ptr = NULL;


	// set up cinematic stuff
	layer = m_layout->find( "cut_scene" );
	rect = layer->get_rect();
	point.x = rect.left;
	point.y = rect.top;

	bool player_is_defender;
	bool player_won;
	
	if ( m_players[k_side_attacker] && !m_players[k_side_attacker]->is_computer() )
	{
		player_is_defender = false;
		player_won = attacker_won( m_result );
	}
	else
	{
		player_is_defender = true;
		player_won = defender_won( m_result );
	}

	std::string destination_name;
	t_adventure_map* map = m_armies[0]->get_map();

	if (map == 0)
		map = m_armies[1]->get_map();

	victor_text = k_victorious;

	// Handle the combat result
	switch (m_result)
	{
		// Check for retreat
		case k_result_attacker_retreated:
		case k_result_defender_retreated:
			if ( player_won )
			{
				text = k_enemy_retreats;
				cinematic_result = k_cinematic_result_player_won_battle;
			}
			else
			{
				text = format_hero_list( *m_armies[player_is_defender], k_one_hero_retreats,
										 k_player_retreats );
				destination_name = get_destination_name( map, 
														 m_players[player_is_defender], 
														 m_location,
														 *m_armies[player_is_defender],
														 m_town );
				text = replace_keywords( text, "%town_name", destination_name );
				cinematic_result = k_cinematic_result_player_retreated; 
			}
			break;


		// Check for surrender or escape (via town gate)
		case k_result_attacker_escaped:
		case k_result_defender_escaped:
			if ( player_won )
			{
				text = k_enemy_heroes_gate;
				cinematic_result = k_cinematic_result_player_won_battle; 
			}
			else
			{
				text = format_hero_list( *m_armies[player_is_defender], k_player_heroes_gate,
										 k_player_heroes_gate );
				destination_name = get_destination_name( map, 
														 m_players[player_is_defender], 
														 m_location,
														 *m_armies[player_is_defender],
														 m_town );
				text = replace_keywords( text, "%town_name", destination_name );
				cinematic_result = k_cinematic_result_player_gated; 
			} 
			break;

		case k_result_attacker_surrendered:
		case k_result_defender_surrendered:
			if ( player_won )
			{
				text = k_enemy_retreats;
				cinematic_result = k_cinematic_result_player_won_battle; 
			}
			else
			{
				destination_name = get_destination_name( map, 
														 m_players[player_is_defender], 
														 m_location,
														 *m_armies[player_is_defender],
														 m_town );
				text = replace_keywords( k_player_surrenders, "%town_name", destination_name );
				cinematic_result = k_cinematic_result_player_surrendered; 
			} 
			break;

		case k_result_attacker_lost:
		case k_result_defender_lost:
			if ( player_won )
			{
				text = k_player_won_battle;
				cinematic_result = k_cinematic_result_player_won_battle;
			}
			else
			{
				text = k_player_loses_battle;
				cinematic_result = k_cinematic_result_enemy_won_battle;
			} 
			break;

		case k_result_both_lost:
			text = k_both_died;
			victor_text = k_defeated;
			cinematic_result = k_cinematic_result_both_lost;
			break;

		default:
			assert( false );
			return;
	}

	if (m_town != 0)
	{
		if (attacker_won( m_result ))
			cinematic_result = k_cinematic_result_player_captured_town;
		else
			cinematic_result = k_cinematic_result_player_defended_town;
	}

	// add "damage" number
	add_text( text, "combat_results_text", 20, true, true );

	// add victorious banner
	add_text( victor_text, "victor", 1 );

	// add defeated banner
	add_text( k_defeated, "defeated", 1 );

	// add creatures lost for victor banner
	add_text( k_creatures_lost_victor, "victor_losses", 1 );

	// add creatures lost for loser banner
	add_text( k_creatures_lost_loser, "defeated_losses", 1 );
}

// ---------------------------------------------------------------------
// combat_results creatures dialog
// ---------------------------------------------------------------------
static t_external_string const k_combat_results_title( "combat_results_title.combat" );
void t_combat_results_dialog::initialize()
{
	m_layout = g_layout.get();
	m_creatures_lost_layout = k_creature_select_bitmaps.get();

	//////////////////////////////////////////////////////////////////
 	// find dimensions & center
	t_screen_point        origin(0,0);
	t_bitmap_layer const* layer = m_layout->find( "background" );
	t_screen_rect		  rect = layer->get_rect();

	set_bitmap( layer );
	rect += t_screen_point( (get_parent()->get_width() - rect.width()) / 2, 
		                           (get_parent()->get_height() - rect.height()) / 2 );
	move( rect );
	set_drop_shadow();

	//////////////////////////////////////////////////////////////////

	// add title
	std::string           text;

	layer = m_layout->find( "title" );
	rect = layer->get_rect();
	m_title = new t_text_window( get_font( rect.height() ), rect, this, 
		                         k_combat_results_title, t_pixel_24(0,0,0) );
	m_title->set_center_horizontal();
	m_title->set_center_vertical();
	m_title->set_drop_shadow( true, t_pixel_24(200,200,200));

	create_text();
	create_icons();
	create_buttons();

	// add title
//	text = replace_keywords( k_text_combat_results_creatures, "%creatures", m_traits->plural_name );
	// make it all upper case
//	std::transform( text.begin(), text.end(), text.begin(), toupper );
//	m_title->set_text( text );

}
